import math
import os
import subprocess
from src.modules.file_manager import FileManager
from src.modules.media_processor import MediaProcessor

class DurationAdjuster:
    """
    处理音频和视频时长不匹配的情况
    """
    
    def __init__(self, startupinfo=None, logger=None):
        """
        初始化DurationAdjuster
        
        :param startupinfo: 用于subprocess的startupinfo对象
        :param logger: 用于记录操作日志的函数
        """
        self.startupinfo = startupinfo
        self.logger = logger
        self.media_processor = MediaProcessor(startupinfo=startupinfo, logger=logger)

    def handle_duration_mismatch(self,
                                 video_path,
                                 audio_path,
                                 temp_dir=None,
                                 transition_effect="fade"
                                 ):
        """
        处理音频和视频时长不匹配的情况，并添加淡出效果
        
        :param video_path: 视频文件路径
        :param audio_path: 音频文件路径
        :param temp_dir: 临时文件目录
        :param add_fade_out: 是否添加淡出效果
        :return: dict: 包含调整后的视频和音频路径
        """
        # 获取媒体时长
        video_duration = self.media_processor.get_media_duration(video_path)
        audio_duration = self.media_processor.get_media_duration(audio_path)
        
        if video_duration is None or audio_duration is None:
            self._log_info(f"无法获取媒体时长，跳过调整")
            return {"video": video_path, "audio": audio_path, "adjusted": False}
            
        self._log_info(f"视频时长: {video_duration:.2f}秒, 音频时长: {audio_duration:.2f}秒")
        
        # 如果时长差异小于1秒，认为基本匹配
        if abs(video_duration - audio_duration) < 1:
            self._log_info(f"视频和音频时长基本匹配，差异: {abs(video_duration - audio_duration):.2f}秒")
            return {"video": video_path, "audio": audio_path, "adjusted": False}
        
        # 视频比音频长
        if video_duration > audio_duration:
            self._log_info(f"视频比音频长 {video_duration - audio_duration:.2f}秒")
            
            # 计算所需的速度因子
            speed_factor = video_duration / audio_duration
            
            # 如果速度因子超过2.5，则限制为2.5并截断多余的视频部分
            if speed_factor > 2.5:
                self._log_info(f"速度因子({speed_factor:.2f})超过2.5，限制为2.5并截断视频")
                
                # 先按2.5倍速处理
                result = self.adjust_video_speed_with_cap(
                    video_path, 
                    audio_duration, 
                    temp_dir, 
                    max_speed_factor=2.5,
                    )
                
                if result["success"]:
                    return {"video": result["output_path"], "audio": audio_path, "adjusted": True, "method": "video_speed_and_trim"}
            else:
                # 速度因子在合理范围内，按原逻辑加速视频
                result = self.adjust_video_speed(
                    video_path, 
                    audio_duration, 
                    temp_dir, 
                )
                
                if result["success"]:
                    return {"video": result["output_path"], "audio": audio_path, "adjusted": True, "method": "video_speed"}
        
        # 音频比视频长 - 重复视频直到匹配音频时长
        else:
            self._log_info(f"音频比视频长 {audio_duration - video_duration:.2f}秒，将循环播放视频")
            result = self.repeat_video_to_match_audio(
                video_path, 
                audio_duration, 
                temp_dir,
                transition_effect=transition_effect
            )
            
            if result["success"]:
                return {"video": result["output_path"], "audio": audio_path, "adjusted": True, "method": "video_repeat"}
        
        # 如果调整失败，返回原始文件
        self._log_warning("调整失败，使用原始文件")
        return {"video": video_path, "audio": audio_path, "adjusted": False}

    def adjust_video_speed(self, video_path, target_duration, temp_dir=None, add_fade_out=True):
        """
        调整视频速度以匹配目标时长，并可选择添加淡出效果
        
        :param video_path: 视频文件路径
        :param target_duration: 目标时长（秒）
        :param temp_dir: 临时文件目录
        :param add_fade_out: 是否添加淡出效果
        :return: dict: 处理结果
        """
        try:
            video_duration = self.media_processor.get_media_duration(video_path)
            if video_duration is None:
                return {"success": False, "message": "无法获取视频时长"}
                
            # 计算速度因子
            speed_factor = video_duration / target_duration
            self._log_info(f"视频加速比例: {speed_factor:.2f}x")
            
            # 检查加速比例是否合理
            if speed_factor > 3.0:
                self._log_warning(f"视频加速比例过高 ({speed_factor:.2f}x)，可能影响质量")
                if speed_factor > 10.0:
                    self._log_error(f"视频加速比例过高 ({speed_factor:.2f}x)，放弃加速处理")
                    return {"success": False, "message": f"加速比例过高: {speed_factor:.2f}x"}
                
            # 创建临时文件路径
            if temp_dir is None:
                temp_dir_obj = FileManager().create_temp_dir(
                    prefix="speed_adjust_",
                )
                temp_dir = temp_dir_obj.path
                
            base_name = os.path.basename(video_path)
            name, ext = os.path.splitext(base_name)
            output_path = os.path.join(temp_dir, f"{name}_speed{ext}")
            
            # 构建处理音频速度的滤镜链
            audio_filter = ""
            remaining_factor = speed_factor
            
            # FFmpeg的atempo滤镜限制在0.5到2.0之间，需要链式处理
            if remaining_factor > 1.0:
                audio_chunks = []
                while remaining_factor > 1.0:
                    chunk = min(2.0, remaining_factor)
                    audio_chunks.append(f"atempo={chunk}")
                    remaining_factor /= chunk
                    
                audio_filter = ",".join(audio_chunks)
            else:
                # 视频需要减速（罕见情况）
                audio_filter = f"atempo={remaining_factor}"
            
            # 计算淡出开始时间（如果需要）
            fade_filter = ""
            fade_audio_filter = ""
            fade_duration = 1.0  # 1秒淡出
            
            if add_fade_out:
                fade_start = max(0, target_duration - fade_duration)
                fade_filter = f",fade=t=out:st={fade_start}:d={fade_duration}:color=black"
                fade_audio_filter = f",afade=t=out:st={fade_start}:d={fade_duration}"
                self._log_info(f"添加淡出效果，开始时间: {fade_start}秒，持续: {fade_duration}秒")
            
            # 构建命令
            cmd = [
                "ffmpeg",
                "-i", video_path,
                "-filter_complex", 
                f"[0:v]setpts={1/speed_factor}*PTS{fade_filter}[v];[0:a]{audio_filter}{fade_audio_filter}[a]",
                "-map", "[v]",
                "-map", "[a]",
                "-c:v", "libx264",
                "-preset", "medium", 
                "-crf", "18",
                "-y",
                output_path
            ]
            
            # 执行命令
            self._log_info(f"执行视频加速命令: {' '.join(cmd)}")
            process = subprocess.run(
                cmd, 
                startupinfo=self.startupinfo,
                stderr=subprocess.PIPE,
                stdout=subprocess.PIPE,
                universal_newlines=True
            )
            
            if process.returncode == 0:
                # 验证结果
                new_duration = self.media_processor.get_media_duration(output_path)
                if new_duration is None:
                    self._log_error("无法获取处理后视频的时长")
                    return {"success": False, "message": "无法验证处理结果"}
                    
                # 检查处理后的时长是否接近目标时长
                duration_diff = abs(new_duration - target_duration)
                if duration_diff > 1.0:  # 允许1秒误差
                    self._log_warning(f"处理后视频时长 ({new_duration:.2f}秒) 与目标时长 ({target_duration:.2f}秒) 相差 {duration_diff:.2f}秒")
                
                self._log_info(f"视频加速成功，新时长: {new_duration:.2f}秒，目标时长: {target_duration:.2f}秒")
                return {"success": True, "output_path": output_path, "duration": new_duration}
            else:
                self._log_error(f"视频加速失败: {process.stderr}")
                return {"success": False, "message": f"视频加速失败: {process.stderr[:200]}..."}
                
        except Exception as e:
            self._log_error(f"调整视频速度时出错: {str(e)}")
            return {"success": False, "message": f"调整视频速度时出错: {str(e)}"}

    # 更新trim_audio方法加入淡出效果
    def trim_audio(self, audio_path, target_duration, temp_dir=None, add_fade_out=True):
        """
        裁剪音频以匹配目标时长，并可选择添加淡出效果
        
        :param audio_path: 音频文件路径
        :param target_duration: 目标时长（秒）
        :param temp_dir: 临时文件目录
        :param add_fade_out: 是否添加淡出效果
        :return: dict: 处理结果
        """
        try:
            audio_duration = self.media_processor.get_media_duration(audio_path)
            if audio_duration is None:
                return {"success": False, "message": "无法获取音频时长"}
                
            # 创建临时文件路径
            if temp_dir is None:
                temp_dir = FileManager().create_temp_dir().path
                
            base_name = os.path.basename(audio_path)
            name, ext = os.path.splitext(base_name)
            output_path = os.path.join(temp_dir, f"{name}_trimmed.m4a")  # 使用.m4a确保容器格式正确
            
            # 构建滤镜链
            filter_chains = []
            
            # 添加淡出效果（如果需要）
            if add_fade_out:
                fade_duration = min(1.0, target_duration / 3)  # 确保淡出时长合理
                fade_start = max(0, target_duration - fade_duration)
                filter_chains.append(f"afade=t=out:st={fade_start}:d={fade_duration}")
                self._log_info(f"添加音频淡出效果，开始时间: {fade_start}秒，持续: {fade_duration}秒")
            
            # 将裁剪也添加到滤镜链中
            filter_chains.append(f"atrim=0:{target_duration}")
            
            # 构建命令
            cmd = ["ffmpeg", "-i", audio_path]
            
            # 添加滤镜链
            if filter_chains:
                cmd.extend(["-af", ",".join(filter_chains)])
            
            # 明确指定输出格式
            cmd.extend([
                "-c:a", "aac",
                "-b:a", "128k",  # 降低比特率避免编码问题
                "-f", "mp4",     # 强制使用MP4容器
                "-y",
                output_path
            ])
            
            # 执行命令
            self._log_info(f"执行音频裁剪命令: {' '.join(cmd)}")
            process = subprocess.run(
                cmd, 
                startupinfo=self.startupinfo,
                stderr=subprocess.PIPE,
                stdout=subprocess.PIPE,
                universal_newlines=True
            )
            
            if process.returncode == 0:
                # 验证结果
                new_duration = self.media_processor.get_media_duration(output_path)
                self._log_info(f"音频裁剪成功，新时长: {new_duration:.2f}秒")
                return {"success": True, "output_path": output_path, "duration": new_duration}
            else:
                # 尝试备用方法
                self._log_warning(f"主要裁剪方法失败: {process.stderr}")
                self._log_info("尝试备用音频裁剪方法...")
                
                # 更简单的命令
                alt_output_path = os.path.join(temp_dir, f"{name}_trimmed_alt.m4a")
                alt_cmd = [
                    "ffmpeg",
                    "-i", audio_path,
                    "-ss", "0",
                    "-t", str(target_duration),
                    "-c:a", "aac",
                    "-b:a", "128k",
                    "-y",
                    alt_output_path
                ]
                
                self._log_info(f"备用裁剪命令: {' '.join(alt_cmd)}")
                alt_process = subprocess.run(
                    alt_cmd,
                    startupinfo=self.startupinfo,
                    stderr=subprocess.PIPE,
                    stdout=subprocess.PIPE,
                    universal_newlines=True
                )
                
                if alt_process.returncode == 0:
                    new_duration = self.media_processor.get_media_duration(alt_output_path)
                    self._log_info(f"备用音频裁剪成功，新时长: {new_duration:.2f}秒")
                    return {"success": True, "output_path": alt_output_path, "duration": new_duration}
                else:
                    self._log_error(f"备用裁剪也失败: {alt_process.stderr}")
                    return {"success": False, "message": f"音频裁剪失败: {alt_process.stderr[:200]}..."}
        except Exception as e:
            self._log_error(f"裁剪音频时出错: {str(e)}")
            return {"success": False, "message": f"裁剪音频时出错: {str(e)}"}

    def _log_info(self, message, level="info"):
        """记录信息级别日志"""
        if self.logger:
            self.logger(message)
        else:
            from src.utils.logger import log_info
            log_info(message)
    
    def _log_error(self, message):
        """记录错误级别日志"""
        if self.logger:
            self.logger(message, level="error")
        else:
            from src.utils.logger import log_error
            log_error(message)
            
    def _log_warning(self, message):
        """记录警告级别日志"""
        if self.logger:
            self.logger(message, level="warning")
        else:
            from src.utils.logger import log_warning
            log_warning(message)
            
    def adjust_video_speed_with_cap(self,
                                video_path,
                                target_duration,
                                temp_dir=None,
                                max_speed_factor=2.5,
                                ):
        """
        调整视频速度至上限，然后截断多余部分以匹配目标时长
        
        :param video_path: 视频文件路径
        :param target_duration: 目标时长（秒）
        :param temp_dir: 临时文件目录
        :param max_speed_factor: 最大速度因子
        :return: dict: 处理结果
        """
        try:
            video_duration = self.media_processor.get_media_duration(video_path)
            if video_duration is None:
                return {"success": False, "message": "无法获取视频时长"}
                
            # 计算速度因子，并限制为最大值
            actual_speed_factor = min(video_duration / target_duration, max_speed_factor)
            self._log_info(f"将视频加速 {actual_speed_factor:.2f}x (上限: {max_speed_factor}x)")
            
            # 创建临时文件路径
            if temp_dir is None:
                temp_dir = FileManager().create_temp_dir().path
                
            base_name = os.path.basename(video_path)
            name, ext = os.path.splitext(base_name)
            
            # 先加速视频
            sped_up_file = FileManager().create_temp_file(
                prefix=f"{name}_speed_",
                suffix=ext,
                in_dir=temp_dir
            )
            
            sped_up_path = sped_up_file.path
            
            # 构建处理音频速度的滤镜链
            audio_filter = ""
            remaining_factor = actual_speed_factor
            
            # FFmpeg的atempo滤镜限制在0.5到2.0之间，需要链式处理
            if remaining_factor > 1.0:
                audio_chunks = []
                while remaining_factor > 1.0:
                    chunk = min(2.0, remaining_factor)
                    audio_chunks.append(f"atempo={chunk}")
                    remaining_factor /= chunk
                    
                audio_filter = ",".join(audio_chunks)
            else:
                audio_filter = f"atempo={remaining_factor}"
            
            # 构建命令
            cmd = [
                "ffmpeg",
                "-i", video_path,
                "-filter_complex", f"[0:v]setpts={1/actual_speed_factor}*PTS[v];[0:a]{audio_filter}[a]",
                "-map", "[v]",
                "-map", "[a]",
                "-c:v", "libx264",
                "-preset", "medium", 
                "-crf", "18",
                "-y",
                sped_up_path
            ]
            
            # 执行命令
            self._log_info(f"执行视频加速命令")
            process = subprocess.run(
                cmd, 
                startupinfo=self.startupinfo,
                stderr=subprocess.PIPE,
                stdout=subprocess.PIPE,
                universal_newlines=True
            )
            
            if process.returncode != 0:
                self._log_error(f"视频加速失败: {process.stderr}")
                return {"success": False, "message": f"视频加速失败: {process.stderr[:200]}..."}
            
            # 计算加速后的视频时长
            accelerated_duration = video_duration / actual_speed_factor
            
            # 如果加速后视频仍然比目标时长长，需要截断
            if accelerated_duration > target_duration + 0.5:  # 添加0.5秒容差
                self._log_info(f"加速后视频时长({accelerated_duration:.2f}秒)仍超过目标({target_duration:.2f}秒)，截断多余部分")
                
                # 输出路径
                trimmed_file = FileManager().create_temp_file(
                    prefix=f"{name}_trimmed_",
                    suffix=ext,
                    in_dir=temp_dir
                )
                output_path = trimmed_file.path
                
                # 截断命令
                trim_cmd = [
                    "ffmpeg",
                    "-i", sped_up_path,
                    "-ss", "0",
                    "-t", str(target_duration),
                    "-c:v", "copy",  # 无需重新编码
                    "-c:a", "copy",
                    "-y",
                    output_path
                ]
                
                # 执行截断
                self._log_info(f"执行视频截断命令")
                trim_process = subprocess.run(
                    trim_cmd, 
                    startupinfo=self.startupinfo,
                    stderr=subprocess.PIPE,
                    stdout=subprocess.PIPE,
                    universal_newlines=True
                )
                
                if trim_process.returncode != 0:
                    self._log_error(f"视频截断失败: {trim_process.stderr}")
                    # 如果截断失败，返回加速后的视频
                    return {"success": True, "output_path": sped_up_path, "message": "视频加速成功，但截断失败"}
                
                return {"success": True, "output_path": output_path, "duration": target_duration}
            else:
                output_path = sped_up_path
                self._log_info(f"视频加速后时长({accelerated_duration:.2f}秒)接近目标时长({target_duration:.2f}秒)，不需要截断")
                return {"success": True, "output_path": output_path, "duration": accelerated_duration}
                
        except Exception as e:
            self._log_error(f"处理视频速度和截断时出错: {str(e)}")
            return {"success": False, "message": f"处理视频速度和截断时出错: {str(e)}"}
   
    def repeat_video_to_match_audio(self,
                                    video_path,
                                    target_duration,
                                    temp_dir=None,
                                    transition_effect="fade"
                                ):
        """
        重复视频内容直到匹配目标时长，并添加过渡特效
        
        :param video_path: 视频文件路径
        :param target_duration: 目标时长（秒）
        :param temp_dir: 临时文件目录
        :param transition_effect: 过渡特效类型
        :return: dict: 处理结果
        """
        try:
            video_duration = self.media_processor.get_media_duration(video_path)
            if video_duration is None:
                return {"success": False, "message": "无法获取视频时长"}
                
            # 计算需要重复多少次
            repeat_count = math.ceil(target_duration / video_duration)
            self._log_info(f"视频需要重复 {repeat_count} 次才能匹配音频时长")
            
            # 创建临时文件路径
            if temp_dir is None:
                temp_dir = FileManager().create_temp_dir().path
            
            base_name = os.path.basename(video_path)
            name, ext = os.path.splitext(base_name)
            
            # 创建一个包含重复视频路径的列表文件
            concat_file = os.path.join(temp_dir, f"concat_{name}.txt")
            with open(concat_file, 'w') as f:
                for _ in range(repeat_count):
                    f.write(f"file '{video_path.replace('\\', '/')}'\n")
            
            # 创建最终输出文件
            final_output_file = FileManager().create_temp_file(
                prefix=f"{name}_final_",
                suffix=ext,
                in_dir=temp_dir
            )
            final_output_path = final_output_file.path
            
            # 计算淡出参数
            fade_duration = min(1.0, target_duration / 4)  # 淡出时长，但不超过视频时长的1/4
            fade_start = max(0, target_duration - fade_duration)
            
            # 获取过渡滤镜
            transition_filter = self._get_transition_filter(
                transition_effect,
                fade_start,
                fade_duration
            )
            
            # 构建一个完整的命令：concat -> 裁剪 -> 添加特效
            cmd = [
                "ffmpeg",
                "-f", "concat",
                "-safe", "0",
                "-i", concat_file,
                "-ss", "0",
                "-t", str(target_duration),
                "-vf", transition_filter,
                "-af", f"afade=t=out:st={fade_start}:d={fade_duration}",
                "-c:v", "libx264",
                "-preset", "medium", 
                "-crf", "18",
                "-y",
                final_output_path
            ]
            
            # 执行命令
            self._log_info(f"执行视频重复、裁剪并添加特效的命令: {' '.join(cmd)}")
            process = subprocess.run(
                cmd, 
                startupinfo=self.startupinfo,
                stderr=subprocess.PIPE,
                stdout=subprocess.PIPE,
                universal_newlines=True
            )
            
            if process.returncode != 0:
                self._log_error(f"视频处理失败: {process.stderr}")
                return {"success": False, "message": f"视频处理失败: {process.stderr[:200]}..."}
            
            # 删除临时的concat文件
            try:
                os.remove(concat_file)
            except Exception as e:
                self._log_warning(f"清理临时文件失败: {str(e)}")
            
            # 添加短暂延迟确保文件可访问
            import time
            time.sleep(0.2)
            
            self._log_info(f"视频重复、裁剪和特效添加成功: {final_output_path}")
            return {"success": True, "output_path": final_output_path, "duration": target_duration}
            
        except Exception as e:
            self._log_error(f"处理视频内容时出错: {str(e)}")
            return {"success": False, "message": f"处理视频内容时出错: {str(e)}"}
  
    # 替换现有的淡出滤镜设置
    def _get_transition_filter(self, effect_type, start_time, duration):
        """根据过渡效果类型返回适当的FFmpeg滤镜"""
        if effect_type == "fade":
            return f"fade=t=out:st={start_time}:d={duration}:color=black"
        elif effect_type == "circlecrop":
            return f"fade=t=out:st={start_time}:d={duration}:color=black,circlecrop=iw/2:ih/2:iw/2:oh*{start_time}/{duration}"
        elif effect_type == "wipeleft":
            # 计算每帧移动的像素数 (宽度/持续时间/帧率)
            return f"crop=iw-iw*{duration}/(t-{start_time}):ih:0:0"
        elif effect_type == "wiperight":
            return f"crop=iw*{duration}/(t-{start_time}):ih:iw-iw*{duration}/(t-{start_time}):0"
        elif effect_type == "wipeup":
            return f"crop=iw:ih-ih*{duration}/(t-{start_time}):0:0"
        elif effect_type == "wipedown":
            return f"crop=iw:ih*{duration}/(t-{start_time}):0:ih-ih*{duration}/(t-{start_time})"
        elif effect_type == "dissolve":
            return f"fade=t=out:st={start_time}:d={duration}:alpha=1"
        else:
            # 默认使用淡出
            return f"fade=t=out:st={start_time}:d={duration}:color=black"